package edu.client;

import java.util.Date;
import java.util.LinkedList;
import java.util.List;

import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ChangeHandler;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.AbsolutePanel;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HasHorizontalAlignment;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.LayoutPanel;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.ScrollPanel;
import com.google.gwt.user.client.ui.SimpleCheckBox;
import com.google.gwt.user.client.ui.TabPanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.ValueBoxBase.TextAlignment;

import edu.client.ComprasService.ComprasService;
import edu.client.ComprasService.ComprasServiceAsync;
import edu.shared.DTO.MedidaVariableEstandarDTO;
import edu.shared.DTO.ProductoDTO;
import edu.shared.DTO.RequerimientoCompraDTO;

public class P_SolicitarPresupuesto extends Composite{
	
	//columnas para la tabla requerimientos de compra
	private static final int COL_CHECK_RC = 0;
	private static final int COL_ELEMENTO_RC = 1;
	private static final int COL_MATERIAL_RC = 2;
	private static final int COL_MEDIDA_FIJA_RC = 3;
	private static final int COL_MEDIDA_VARIABLE_1_RC = 4;
	private static final int COL_MEDIDA_VARIABLE_2_RC = 5;
	private static final int COL_CANTIDAD_REQUERIDA_RC = 6;
	private static final int COL_CANTIDAD_COMPRAR_RC = 7;
	private static final int COL_FECHA_REQUERIMIENTO_COMPRA_RC = 8;
	
	//columnas para la tabla productos adicionales
	private static final int COL_ELEMENTO_PA = 0;
	private static final int COL_MATERIAL_PA = 1;
	private static final int COL_MEDIDA_FIJA_PA = 2;
	private static final int COL_MEDIDA_VARIABLE_1_PA = 3;
	private static final int COL_MEDIDA_VARIABLE_2_PA = 4;
	private static final int COL_CANTIDAD_COMPRAR_PA = 5;
	private static final int COL_ELIMINAR_PA = 6;
	
	//componentes de la pantalla
	private ListBox cbElemento;
	private ListBox cbMaterial;
	private ListBox cbMedidaFija;
	private ListBox cbMedidasEstandares;
	private TextBox tbCantidad;
	private FlexTable ftProductosAdicionales;
	private FlexTable ftRequerimientosCompra;
	private Button btnAgregar;
	
	private TabPanel tpPadre;
	private List<RequerimientoCompraDTO> requerimientos;
	private List<RequerimientoCompraDTO> requerimientosComprimidos;
	private List<List<Integer>> ids;
	private List<ProductoDTO> productos;
	private List<ProductoDTO> productosAdicionales;
	private ComprasServiceAsync comprasService;
	
	public P_SolicitarPresupuesto(TabPanel padre) {
		
		this.tpPadre = padre;
		comprasService = GWT.create(ComprasService.class);
		productosAdicionales = new LinkedList<ProductoDTO>();
		requerimientosComprimidos = new LinkedList<RequerimientoCompraDTO>();
		
		LayoutPanel layoutPanel = new LayoutPanel();
		initWidget(layoutPanel);
		layoutPanel.setSize((Window.getClientWidth() - 55) + "px", "926px");
				
		Label lblRequerimientosCompra = new Label("REQUERIMIENTOS DE COMPRA");
		lblRequerimientosCompra.setStyleName("labelTitulo");
		layoutPanel.add(lblRequerimientosCompra);
		layoutPanel.setWidgetLeftWidth(lblRequerimientosCompra, 2.5, Unit.PCT, 95.0, Unit.PCT);
		layoutPanel.setWidgetTopHeight(lblRequerimientosCompra, 15.0, Unit.PX, 50.0, Unit.PX);
		
		ScrollPanel scrollPanelRequerimientosCompra = new ScrollPanel();
		scrollPanelRequerimientosCompra.setStyleName("tabla");
		layoutPanel.add(scrollPanelRequerimientosCompra);
		layoutPanel.setWidgetLeftWidth(scrollPanelRequerimientosCompra, 5.0, Unit.PCT, 90.0, Unit.PCT);
		layoutPanel.setWidgetTopHeight(scrollPanelRequerimientosCompra, 85.0, Unit.PX, 250.0, Unit.PX);
		
		ftRequerimientosCompra = new FlexTable();
		scrollPanelRequerimientosCompra.setWidget(ftRequerimientosCompra);
		ftRequerimientosCompra.setSize("100%", "100%");
		
		//cargamos el encabezado de la tabla
		// columna de checkeo
		ftRequerimientosCompra.setText(0, COL_CHECK_RC, "");
		ftRequerimientosCompra.getCellFormatter().setWidth(0, COL_CHECK_RC, "5%");
		
		// columna elemento
		ftRequerimientosCompra.setText(0, COL_ELEMENTO_RC, "ELEMENTO");
		ftRequerimientosCompra.getCellFormatter().setWidth(0, COL_ELEMENTO_RC, "20%");
				
		// columna material
		ftRequerimientosCompra.setText(0, COL_MATERIAL_RC, "MATERIAL");
		ftRequerimientosCompra.getCellFormatter().setWidth(0, COL_MATERIAL_RC, "15%");
				
		// columna medida fija
		ftRequerimientosCompra.setText(0, COL_MEDIDA_FIJA_RC, "MEDIDA FIJA");
		ftRequerimientosCompra.getCellFormatter().setWidth(0, COL_MEDIDA_FIJA_RC, "10%");
				
		// columna medida variable 1
		ftRequerimientosCompra.setText(0, COL_MEDIDA_VARIABLE_1_RC, "MEDIDA VARIABLE 1");
		ftRequerimientosCompra.getCellFormatter().setWidth(0, COL_MEDIDA_VARIABLE_1_RC, "10%");
				
		// columna medida variable 2
		ftRequerimientosCompra.setText(0, COL_MEDIDA_VARIABLE_2_RC, "MEDIDA VARIABLE 2");
		ftRequerimientosCompra.getCellFormatter().setWidth(0, COL_MEDIDA_VARIABLE_2_RC, "10%");
				
		// columna cantidad requerida
		ftRequerimientosCompra.setText(0, COL_CANTIDAD_REQUERIDA_RC, "CANTIDAD REQUERIDA");
		ftRequerimientosCompra.getCellFormatter().setWidth(0, COL_CANTIDAD_REQUERIDA_RC, "10%");
		
		// columna cantidad a comprar
		ftRequerimientosCompra.setText(0, COL_CANTIDAD_COMPRAR_RC, "CANTIDAD A COMPRAR");
		ftRequerimientosCompra.getCellFormatter().setWidth(0, COL_CANTIDAD_COMPRAR_RC, "10%");
				
		// columna fecha requerimiento compra
		ftRequerimientosCompra.setText(0, COL_FECHA_REQUERIMIENTO_COMPRA_RC, "FECHA");
		ftRequerimientosCompra.getCellFormatter().setWidth(0, COL_FECHA_REQUERIMIENTO_COMPRA_RC, "10%");	
		
		// seteamos el estilo a los encabezados
		ftRequerimientosCompra.getRowFormatter().addStyleName(0, "tablaEncabezado");
		
		Label lblProductosAdicionales = new Label("PRODUCTOS ADICIONALES");
		lblProductosAdicionales.setStyleName("labelTitulo");
		layoutPanel.add(lblProductosAdicionales);
		layoutPanel.setWidgetLeftWidth(lblProductosAdicionales, 2.5, Unit.PCT, 95.0, Unit.PCT);
		layoutPanel.setWidgetTopHeight(lblProductosAdicionales, 355.0, Unit.PX, 50.0, Unit.PX);
		
		AbsolutePanel materialAP = new AbsolutePanel();
		materialAP.setStyleName("panelConBorde");
		layoutPanel.add(materialAP);
		layoutPanel.setWidgetLeftWidth(materialAP, 8.0, Unit.PCT, 88.0, Unit.PCT);
		layoutPanel.setWidgetTopHeight(materialAP, 420.0, Unit.PX, 90.0, Unit.PX);
				
		Label lblElemento = new Label("ELEMENTO:");
		lblElemento.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_RIGHT);
		layoutPanel.add(lblElemento);
		layoutPanel.setWidgetLeftWidth(lblElemento, 0.0, Unit.PCT, 17.3, Unit.PCT);
		layoutPanel.setWidgetTopHeight(lblElemento, 435.0, Unit.PX, 19.0, Unit.PX);
		
		cbElemento = new ListBox();
		layoutPanel.add(cbElemento);
		layoutPanel.setWidgetLeftWidth(cbElemento, 17.5, Unit.PCT, 25.0, Unit.PCT);
		layoutPanel.setWidgetTopHeight(cbElemento, 430.0, Unit.PX, 32.0, Unit.PX);
		
		cbElemento.addChangeHandler(new ChangeHandler() {
			public void onChange(ChangeEvent event) {
				actualizarComboMaterial();
			}
		});
		
		Label lblMaterial = new Label("MATERIAL:");
		lblMaterial.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_RIGHT);
		layoutPanel.add(lblMaterial);
		layoutPanel.setWidgetLeftWidth(lblMaterial, 50.0, Unit.PCT, 19.8, Unit.PCT);
		layoutPanel.setWidgetTopHeight(lblMaterial, 435.0, Unit.PX, 19.0, Unit.PX);
		
		cbMaterial = new ListBox();
		layoutPanel.add(cbMaterial);
		layoutPanel.setWidgetLeftWidth(cbMaterial, 70.0, Unit.PCT, 25.0, Unit.PCT);
		layoutPanel.setWidgetTopHeight(cbMaterial, 430.0, Unit.PX, 32.0, Unit.PX);
		
		cbMaterial.addChangeHandler(new ChangeHandler() {
			public void onChange(ChangeEvent event) {
				actualizarComboMedidaFija();
			}
		});
		
		Label lblMedidaFija = new Label("MEDIDA FIJA:");
		lblMedidaFija.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_RIGHT);
		layoutPanel.add(lblMedidaFija);
		layoutPanel.setWidgetLeftWidth(lblMedidaFija, 0.0, Unit.PCT, 17.3, Unit.PCT);
		layoutPanel.setWidgetTopHeight(lblMedidaFija, 475.0, Unit.PX, 19.0, Unit.PX);
		
		cbMedidaFija = new ListBox();
		
		cbMedidaFija.addChangeHandler(new ChangeHandler() {
			public void onChange(ChangeEvent event) {
				actualizarComboMedidasEstandar();
			}
		});
		
		layoutPanel.add(cbMedidaFija);
		layoutPanel.setWidgetLeftWidth(cbMedidaFija, 17.5, Unit.PCT, 25.0, Unit.PCT);
		layoutPanel.setWidgetTopHeight(cbMedidaFija, 470.0, Unit.PX, 32.0, Unit.PX);
		
		Label lblMedidaVariable = new Label("MEDIDAS VARIABLES:");
		lblMedidaVariable.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_RIGHT);
		layoutPanel.add(lblMedidaVariable);
		layoutPanel.setWidgetLeftWidth(lblMedidaVariable, 50.0, Unit.PCT, 19.8, Unit.PCT);
		layoutPanel.setWidgetTopHeight(lblMedidaVariable, 475.0, Unit.PX, 19.0, Unit.PX);
		
		cbMedidasEstandares = new ListBox();
		layoutPanel.add(cbMedidasEstandares);
		layoutPanel.setWidgetLeftWidth(cbMedidasEstandares, 70.0, Unit.PCT, 25.0, Unit.PCT);
		layoutPanel.setWidgetTopHeight(cbMedidasEstandares, 470.0, Unit.PX, 32.0, Unit.PX);
		
		Label lblCantidad = new Label("CANTIDAD:");
		lblCantidad.setHorizontalAlignment(HasHorizontalAlignment.ALIGN_RIGHT);
		lblCantidad.setStyleName("gwt-LabelFormulario");
		layoutPanel.add(lblCantidad);
		layoutPanel.setWidgetLeftWidth(lblCantidad, 30.0, Unit.PCT, 7.8, Unit.PCT);
		layoutPanel.setWidgetTopHeight(lblCantidad, 525.0, Unit.PX, 19.0, Unit.PX);
		
		tbCantidad = new TextBox();
		layoutPanel.add(tbCantidad);
		layoutPanel.setWidgetLeftWidth(tbCantidad, 38.0, Unit.PCT, 15.0, Unit.PCT);
		layoutPanel.setWidgetTopHeight(tbCantidad, 520.0, Unit.PX, 32.0, Unit.PX);
		tbCantidad.setAlignment(TextAlignment.CENTER);
		
	
		btnAgregar = new Button();
		btnAgregar.setText("AGREGAR");
				
		btnAgregar.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				try{
					//validamos la cantidad a comprar
					int cantidad = Integer.parseInt(tbCantidad.getText());
					
					if(cantidad <= 0)
						throw new Exception();
					
					//cargamos el producto adicional
					cargarProductoAdicional();
				}
				
				catch(Exception e)
				{
					Window.alert("La cantidad debe ser un número entero mayor a cero.");
				}
			}
		});
		
		layoutPanel.add(btnAgregar);
		layoutPanel.setWidgetLeftWidth(btnAgregar, 55.0, Unit.PCT, 10.0, Unit.PCT);
		layoutPanel.setWidgetTopHeight(btnAgregar, 520.0, Unit.PX, 28.0, Unit.PX);
		
		ScrollPanel scrollPanelProductosAdicionales = new ScrollPanel();
		scrollPanelProductosAdicionales.setStyleName("tabla");
		layoutPanel.add(scrollPanelProductosAdicionales);
		layoutPanel.setWidgetLeftWidth(scrollPanelProductosAdicionales, 5.0, Unit.PCT, 90.0, Unit.PCT);
		layoutPanel.setWidgetTopHeight(scrollPanelProductosAdicionales, 555.0, Unit.PX, 250.0, Unit.PX);
		
		ftProductosAdicionales = new FlexTable();
		scrollPanelProductosAdicionales.setWidget(ftProductosAdicionales);
		ftProductosAdicionales.setSize("100%", "100%");
		
		//cargamos el encabezado de la tabla. Se le resta 1 a la posición de la columna porque
		//el orden de las columnas es igual al de la tabla requerimientos adicionales excepto
		//la primer columna (columna de checkeo).
		
		// columna elemento
		ftProductosAdicionales.setText(0, COL_ELEMENTO_PA, "ELEMENTO");
		ftProductosAdicionales.getCellFormatter().setWidth(0, COL_ELEMENTO_PA, "25%");
				
		// columna material
		ftProductosAdicionales.setText(0, COL_MATERIAL_PA, "MATERIAL");
		ftProductosAdicionales.getCellFormatter().setWidth(0, COL_MATERIAL_PA, "20%");
				
		// columna medida fija
		ftProductosAdicionales.setText(0, COL_MEDIDA_FIJA_PA, "MEDIDA FIJA");
		ftProductosAdicionales.getCellFormatter().setWidth(0, COL_MEDIDA_FIJA_PA, "15%");
				
		// columna medida variable 1
		ftProductosAdicionales.setText(0, COL_MEDIDA_VARIABLE_1_PA, "MEDIDA VARIABLE 1");
		ftProductosAdicionales.getCellFormatter().setWidth(0, COL_MEDIDA_VARIABLE_1_PA, "10%");
				
		// columna medida variable 2
		ftProductosAdicionales.setText(0, COL_MEDIDA_VARIABLE_2_PA, "MEDIDA VARIABLE 2");
		ftProductosAdicionales.getCellFormatter().setWidth(0, COL_MEDIDA_VARIABLE_2_PA, "10%");
		
		// columna cantidad a comprar
		ftProductosAdicionales.setText(0, COL_CANTIDAD_COMPRAR_PA, "CANTIDAD A COMPRAR");
		ftProductosAdicionales.getCellFormatter().setWidth(0, COL_CANTIDAD_COMPRAR_PA, "15%");
		
		// columna medida variable 2
		ftProductosAdicionales.setText(0, COL_ELIMINAR_PA, "");
		ftProductosAdicionales.getCellFormatter().setWidth(0, COL_ELIMINAR_PA, "5%");
		
		// seteamos el estilo a los encabezados
		ftProductosAdicionales.getRowFormatter().addStyleName(0, "tablaEncabezado");
		
		Label pie = new Label("");
		pie.setStyleName("labelTitulo");
		layoutPanel.add(pie);
		layoutPanel.setWidgetLeftWidth(pie, 2.5, Unit.PCT, 95.0, Unit.PCT);
		layoutPanel.setWidgetTopHeight(pie, 805.0, Unit.PX, 50.0, Unit.PX);
		
		Button btnSalir = new Button();
		btnSalir.setText("SALIR");
		
		//al presionar el botón salir
		btnSalir.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				//cerramos la pantalla
				tpPadre.remove(Validaciones.numeroElemento(tpPadre, "SOLICITAR PRESUPUESTO"));	
			}
		});
		
		layoutPanel.add(btnSalir);
		layoutPanel.setWidgetRightWidth(btnSalir, 5.0, Unit.PCT, 10.0, Unit.PCT);
		layoutPanel.setWidgetBottomHeight(btnSalir, 15.0, Unit.PX, 28.0, Unit.PX);
		
		Button btnImprimir = new Button("");
		btnImprimir.setText("IMPRIMIR");
		
		//al presionar el botón imprimir
		btnImprimir.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				
				int productosCargados = productosCargados();
				
				if(productosCargados == 0)
					Window.alert("Seleecione un requerimiento de compra o carga un producto adicional.");
				
				else if(validarCantidades())
					imprimir();
			}
		});
		
		layoutPanel.add(btnImprimir);
		layoutPanel.setWidgetRightWidth(btnImprimir, 17.5, Unit.PCT, 10.0, Unit.PCT);
		layoutPanel.setWidgetBottomHeight(btnImprimir, 15.0, Unit.PX, 28.0, Unit.PX);
		
				
		cargarRequerimientosCompra();
		cargarProductosAdicionales();
	}
	
	
	/**
	 * Método que carga la tabla de requerimientos de compras relacionados a productos
	 * que puede proveer el proveedor seleccionado. Es decir, sólo se muestran los requerimientos de compra
	 * cuyos productos los vende el proveedor seleccionado.
	 */
	private void cargarRequerimientosCompra()
	{						
		comprasService.buscarRequerimientosCompra("< TODOS >", new AsyncCallback<List<RequerimientoCompraDTO>>()
		{

			@Override
			public void onFailure(Throwable caught) {
				Window.alert("ERROR EN EL SERVICIO." + '\n' + '\n' + caught.getMessage());				
			}

			@Override
			public void onSuccess(List<RequerimientoCompraDTO> result) {
				requerimientos = result;
				
				requerimientosComprimidos = comprimirRequerimientos(requerimientos);
				
				//se utiliza para formatear fechas
				DateTimeFormat formatoFecha = DateTimeFormat.getFormat("dd/MM/yyyy");
				
				int numeroFila = 1;
				
				for(RequerimientoCompraDTO requerimiento : requerimientosComprimidos)
				{
					ProductoDTO producto = requerimiento.getRequerimientoMaterial().getProducto();
					
					//columna check
					ftRequerimientosCompra.setWidget(numeroFila, COL_CHECK_RC, new SimpleCheckBox());
					ftRequerimientosCompra.getFlexCellFormatter().setHorizontalAlignment(numeroFila, COL_CHECK_RC, HasHorizontalAlignment.ALIGN_CENTER);

					//columna elemento
					ftRequerimientosCompra.setWidget(numeroFila, COL_ELEMENTO_RC, new Label(producto.getElemento().getNombre()));
					ftRequerimientosCompra.getCellFormatter().setWordWrap(numeroFila, COL_ELEMENTO_RC, true);
					
					//columna material
					ftRequerimientosCompra.setWidget(numeroFila, COL_MATERIAL_RC, new Label(producto.getMaterial().getNombre()));
					ftRequerimientosCompra.getCellFormatter().setWordWrap(numeroFila, COL_MATERIAL_RC, true);
					
					// columna medida fija
					ftRequerimientosCompra.setWidget(numeroFila, COL_MEDIDA_FIJA_RC, new Label(producto.getMedidaFija().getMedida()));
					ftRequerimientosCompra.getCellFormatter().setWordWrap(numeroFila, COL_MEDIDA_FIJA_RC, true);
			
					// columna medida variable 1
					ftRequerimientosCompra.setWidget(numeroFila, COL_MEDIDA_VARIABLE_1_RC, new Label(String.valueOf(requerimiento.getMedidaVariable1())));
					ftRequerimientosCompra.getCellFormatter().setWordWrap(numeroFila, COL_MEDIDA_VARIABLE_1_RC, true);

					// columna medida variable 2
					ftRequerimientosCompra.setWidget(numeroFila, COL_MEDIDA_VARIABLE_2_RC, new Label(String.valueOf(requerimiento.getMedidaVariable2())));
					ftRequerimientosCompra.getCellFormatter().setWordWrap(numeroFila, COL_MEDIDA_VARIABLE_2_RC, true);
					
					// columna cantidad requerida
					ftRequerimientosCompra.setWidget(numeroFila, COL_CANTIDAD_REQUERIDA_RC, new Label(String.valueOf(requerimiento.getCantidadRequerida())));
					ftRequerimientosCompra.getCellFormatter().setWordWrap(numeroFila, COL_CANTIDAD_REQUERIDA_RC, true);
					
					// creamos el campo de texto para la cantidad a comprar
					final TextBox cantidadAComprar = new TextBox();
					cantidadAComprar.setSize("85%", "85%");
					cantidadAComprar.setText("0");
					cantidadAComprar.setStyleName("textBoxTabla");
					
					//cuando cambia el valor del campo de texto
					cantidadAComprar.addChangeHandler(new ChangeHandler() {
						public void onChange(ChangeEvent event) {
							if(cantidadAComprar.getText().equals(""))
								cantidadAComprar.setText("0");
						}
					});
					
					// columna cantidad a comprar
					ftRequerimientosCompra.setWidget(numeroFila, COL_CANTIDAD_COMPRAR_RC, cantidadAComprar );
					ftRequerimientosCompra.getCellFormatter().setWordWrap(numeroFila, COL_CANTIDAD_COMPRAR_RC, true);
					
					// columna fecha requerimiento de compra
					ftRequerimientosCompra.setWidget(numeroFila, COL_FECHA_REQUERIMIENTO_COMPRA_RC, new Label(formatoFecha.format(requerimiento.getFechaRequerimientoCompra())));
					ftRequerimientosCompra.getCellFormatter().setWordWrap(numeroFila, COL_FECHA_REQUERIMIENTO_COMPRA_RC, true);
					
					//seteamos el estilo de renglón de tabla
					ftRequerimientosCompra.getRowFormatter().setStyleName(numeroFila, "tablaRenglon");
					
					numeroFila++;
				}
				
			}
	
		});
	}
	
	/**
	 * Método que carga las listas deplegables con los productos adicionales que se pueden solicitar.
	 */
	private void cargarProductosAdicionales()
	{					
		comprasService.buscarProductosProvistos("< TODOS >", new AsyncCallback<List<ProductoDTO>>(){

			@Override
			public void onFailure(Throwable caught) {
				Window.alert("ERROR EN EL SERVICIO." + '\n' + '\n' + caught.getMessage());
			}

			@Override
			public void onSuccess(List<ProductoDTO> result) {
				productos = result;
				
				//cargamos todos los elementos de la lista de productos
				for(ProductoDTO producto : productos)
					if(!existeItem(cbElemento, producto.getElemento().getNombre()))
						cbElemento.addItem(producto.getElemento().getNombre());
				
				//sólo actualizamos los combos si hay productos adicionales disponibles
				if(productos.size() > 0)
				{
					btnAgregar.setEnabled(true);
					actualizarComboMaterial();
				}
				
				//caso contrario limpiamos los combos y desabilitamos el botón agregar
				else
				{
					cbMaterial.clear();
					cbElemento.clear();
					cbMedidaFija.clear();
					cbMedidasEstandares.clear();
					
					btnAgregar.setEnabled(false);
				}
			}	
		});
	}
	
	/**
	 * Método que actualiza el combobox de materiales dependiendo del elemento seleccionado
	 */
	private void actualizarComboMaterial()
	{		
		//vaciamos el combo de materiales
		cbMaterial.clear();
		
		//buscamos el elemento seleccionado en el combo de elementos
		String elementoSeleccionado = cbElemento.getValue(cbElemento.getSelectedIndex());
		
		//buscamos los productos cuyo elemento coincide con el seleccionado
		for(ProductoDTO producto : productos){
			
			//si el elemento del producto es igual al seleccionado, agregamos su material al combo de materiales
			if(producto.getElemento().getNombre().equals(elementoSeleccionado))
				if(!existeItem(cbMaterial, producto.getMaterial().getNombre()))
					cbMaterial.addItem(producto.getMaterial().getNombre());
		}
		
		actualizarComboMedidaFija();
	}
	
	
	/**
	 * Método que actualiza el combobox de medidas fijas dependiendo del elemento y el material seleccionado
	 */
	private void actualizarComboMedidaFija()
	{		
		//vaciamos el combo de medidas fijas
		cbMedidaFija.clear();
		
		//buscamos el elemento y el material seleccionado en los combos
		String elementoSeleccionado = cbElemento.getValue(cbElemento.getSelectedIndex());
		String materialSeleccionado = cbMaterial.getValue(cbMaterial.getSelectedIndex());
		
		//buscamos los productos cuyo elemento y material coincide con los seleccionados
		for(ProductoDTO producto : productos){
			
			//si el elemento y el material del producto es igual al seleccionado, agregamos su medida fija al combo de medidas fijas
			if(producto.getElemento().getNombre().equals(elementoSeleccionado) && producto.getMaterial().getNombre().equals(materialSeleccionado))
				if(!existeItem(cbMedidaFija, producto.getMedidaFija().getMedida()))
				cbMedidaFija.addItem(producto.getMedidaFija().getMedida());
		}
				
		actualizarComboMedidasEstandar();
	}
	
	
	/**
	 * Método que actualiza el combobox de medidas variables dependiendo del elemento, material y medida fija seleccionados 
	 */
	private void actualizarComboMedidasEstandar()
	{
		LinkedList<String> medidasEstandar = new LinkedList<String>();
		
		//vaciamos el combo de medidas estándar
		cbMedidasEstandares.clear();
		
		//buscamos el elemento, material y medida fija seleccionados en los combos
		String elementoSeleccionado = cbElemento.getValue(cbElemento.getSelectedIndex());
		String materialSeleccionado = cbMaterial.getValue(cbMaterial.getSelectedIndex());
		String medidaFijaSeleccionada = cbMedidaFija.getValue(cbMedidaFija.getSelectedIndex());
		
		//buscamos los productos cuyo elemento, material y medida fija coincide con los seleccionados
		for(ProductoDTO producto : productos){
						
			//si el elemento, el material y la medida fija del producto es igual al seleccionado,
			//agregamos su medida variable 1 al combo de medidas variables 1
			if(producto.getElemento().getNombre().equals(elementoSeleccionado) && producto.getMaterial().getNombre().equals(materialSeleccionado) && producto.getMedidaFija().getMedida().equals(medidaFijaSeleccionada))
			{
				String medidaEstandar;
				
				for(MedidaVariableEstandarDTO medida : producto.getMedidasEstandar())
				{
					//si las medidas del producto tienen una sola dimensión
					if(!producto.getElemento().getTipoDimension().equals("SUPERFICIE"))
						medidaEstandar = medida.getMedidaVariable1() + "";
					
					else
						medidaEstandar = medida.getMedidaVariable1() + "x" + medida.getMedidaVariable2();
						
					//verificamos que no carguemos dos veces la misma medida estándar
					if(!medidasEstandar.contains(medidaEstandar))
						medidasEstandar.add(medidaEstandar);
				}					
			}	
		}
		
		//cargamos las medidas estándares en el combo de medidas variables
		for(String medida : medidasEstandar)
			cbMedidasEstandares.addItem(medida);		
	}
	
	
	/**
	 * Método que carga un nuevo producto en la tabla de requerimientos adicionales.
	 */
	private void cargarProductoAdicional()
	{
		ProductoDTO productoDTO = new ProductoDTO();
		
		//buscamos el elemento, material, medida fija y medidas estándares seleccionados en los combos
		String elementoSeleccionado = cbElemento.getValue(cbElemento.getSelectedIndex());
		String materialSeleccionado = cbMaterial.getValue(cbMaterial.getSelectedIndex());
		String medidaFijaSeleccionada = cbMedidaFija.getValue(cbMedidaFija.getSelectedIndex());
		String medidasEstandaresSeleccionada = cbMedidasEstandares.getValue(cbMedidasEstandares.getSelectedIndex());
		
		
		//buscamos los productos cuyo elemento, material y medida fija coincide con los seleccionados
		int i = 0;
		boolean encontro = false;
		
		while(i < productos.size() && !encontro)		
		{
			ProductoDTO p = productos.get(i);
			
			//si el elemento, el material y la medida fija del producto es igual al seleccionado,
			//agregamos su medida variable 1 al combo de medidas variables 1
			if(p.getElemento().getNombre().equals(elementoSeleccionado) && p.getMaterial().getNombre().equals(materialSeleccionado) && p.getMedidaFija().getMedida().equals(medidaFijaSeleccionada))
			{				
				productoDTO.setIdProducto(p.getIdProducto());
				productoDTO.getElemento().setNombre(elementoSeleccionado);
				productoDTO.getMaterial().setNombre(materialSeleccionado);
				productoDTO.getMedidaFija().setMedida(medidaFijaSeleccionada);
			
				encontro = true;
			}
			
			i++;
		}
		
		
		//cargamos la medidas medidas variables al producto adicional
		String[] medidasVariables = medidasEstandaresSeleccionada.split("x");
		
		productoDTO.setMedidaVariable1(Double.valueOf(medidasVariables[0]));
		
		//si el producto tiene dos medidas variables el split devolverá un array de longitud 2
		if(medidasVariables.length > 1)
			productoDTO.setMedidaVariable2(Double.valueOf(medidasVariables[1]));
		
		//sino será un array de una posición y sabremos que la medida variable 2 es 0.0
		else
			productoDTO.setMedidaVariable2(0.0);
		
		
		//si no se ha cargado el producto a la tabla de productos adicionales
		if(!existeProductoAdicional(productoDTO))
			agregarFilaTabla(productoDTO);
				
		else
			Window.alert("EL PRODUCTO YA HA SIDO INCLUÍDO EN LOS PRODUCTOS ADICIONALES.");
	}
	
	
	/**
	 * Método que elimina un producto adicional para la orden de compra
	 * @param filaSeleccionada. Fila de la tabla que contiene los productos adicionales
	 */
	private void eliminarProductoAdicional(int filaSeleccionada) {
		
		//eliminamos la fila de la tabla
		ftProductosAdicionales.removeRow(filaSeleccionada);
		
		//se borra el producto de la lista de productos adicionales.
		//se resta 1 a la fila seleccionada porque la fila 0 es el encabezado
		productosAdicionales.remove(filaSeleccionada-1);								
	}
	
	
	/**
	 * Método que agrega en la tabla un nuevo producto.
	 * @param productoDTO. Es el producto a agregar en la tabla.
	 */
	private void agregarFilaTabla(ProductoDTO productoDTO)
	{
		// cargamos el producto a la tabla
		int numeroFila = ftProductosAdicionales.getRowCount();		
		
		//columna elemento
		ftProductosAdicionales.setWidget(numeroFila, COL_ELEMENTO_PA, new Label(productoDTO.getElemento().getNombre()));
		ftProductosAdicionales.getCellFormatter().setWordWrap(numeroFila, COL_ELEMENTO_PA, true);
		
		// columna material
		ftProductosAdicionales.setWidget(numeroFila, COL_MATERIAL_PA, new Label(productoDTO.getMaterial().getNombre()));
		ftProductosAdicionales.getCellFormatter().setWordWrap(numeroFila, COL_MATERIAL_PA, true);

		// columna medida fija
		ftProductosAdicionales.setWidget(numeroFila, COL_MEDIDA_FIJA_PA, new Label(productoDTO.getMedidaFija().getMedida()));
		ftProductosAdicionales.getCellFormatter().setWordWrap(numeroFila, COL_MEDIDA_FIJA_PA, true);

		// columna medida variable 1
		ftProductosAdicionales.setWidget(numeroFila, COL_MEDIDA_VARIABLE_1_PA, new Label(String.valueOf(productoDTO.getMedidaVariable1())));
		ftProductosAdicionales.getCellFormatter().setWordWrap(numeroFila, COL_MEDIDA_VARIABLE_1_PA, true);

		// columna medida variable 2
		ftProductosAdicionales.setWidget(numeroFila, COL_MEDIDA_VARIABLE_2_PA, new Label(String.valueOf(productoDTO.getMedidaVariable2())));
		ftProductosAdicionales.getCellFormatter().setWordWrap(numeroFila, COL_MEDIDA_VARIABLE_2_PA, true);
		
		// columna cantidad a comprar
		ftProductosAdicionales.setWidget(numeroFila, COL_CANTIDAD_COMPRAR_PA, new Label(tbCantidad.getText()));
		ftProductosAdicionales.getCellFormatter().setWordWrap(numeroFila, COL_CANTIDAD_COMPRAR_PA, true);

		
		//creamos un label que muestra una cruz roja
		Label lblEliminar = new Label("");
		lblEliminar.setSize("16px", "16px");
		lblEliminar.setStyleName("labelBorrar");
		
		lblEliminar.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				int filaSeleccionada = ftProductosAdicionales.getCellForEvent(event).getRowIndex();
			
				eliminarProductoAdicional(filaSeleccionada); 
			}
		});
		
		
		//columna eliminar
		ftProductosAdicionales.setWidget(numeroFila, COL_ELIMINAR_PA, lblEliminar);
		ftProductosAdicionales.getFlexCellFormatter().setHorizontalAlignment(numeroFila, COL_ELIMINAR_PA, HasHorizontalAlignment.ALIGN_CENTER);
		
		//seteamos el estilo de renglón de tabla
		ftProductosAdicionales.getRowFormatter().setStyleName(numeroFila, "tablaRenglon");
		
		//limipiamos el campo cantidad
		tbCantidad.setText("");
		
		//agregamos el nuevo producto a la lista de productos adicionales
		productosAdicionales.add(productoDTO);			
	}
	
	
	/**
	 * Método que compara el producto a agregar con cada producto adicional de la lista de productos adicionales
	 * @param productoDTO. Producto a agragar a la lista de productos adicionales
	 * @return encontrado. Valor booleano que indica si el producto a agregar pertenece o no a la lista de productos adicionales.
	 */
	private boolean existeProductoAdicional(ProductoDTO productoDTO)
	{
		boolean encontrado = false;
		int i = 0;
		
		while(i < productosAdicionales.size() && !encontrado)
		{
			//obtenemos las propiedades del producto adicional de la tabla
			ProductoDTO p = productosAdicionales.get(i);
			String elemento = p.getElemento().getNombre();
			String material = p.getMaterial().getNombre();
			String medidaFija = p.getMedidaFija().getMedida();
			double medidaVariable1 = p.getMedidaVariable1();
			double medidaVariable2 = p.getMedidaVariable2();
			
			//comparamos con el producto a cargar en la tabla para ver si es igual
			if(productoDTO.getElemento().getNombre().equals(elemento) && productoDTO.getMaterial().getNombre().equals(material) && productoDTO.getMedidaFija().getMedida().equals(medidaFija) && productoDTO.getMedidaVariable1() == medidaVariable1 && productoDTO.getMedidaVariable2() == medidaVariable2)
				encontrado = true;
			
			i++;
		}
		
		return encontrado;
	}
		
	/**
	 * Método que indica si un combobox contiene un item.
	 * @param combo. Combobox con items.
	 * @param item. Item a buscar.
	 * @return boolean. Retorna true si el combobox contiene el item; false en caso contrario.
	 */
	private boolean existeItem(ListBox combo, String item)
	{
		boolean existe = false;
		int i = 0;
		
		while(i < combo.getItemCount() && !existe)
		{
			if(combo.getValue(i).equals(item))
				existe = true;
			
			i++;
		}
		
		return existe;
	}
	
	/**
	 * Método que recorre la lista de requerimiento de compras y los comprime teniendo en cuenta el producto requerido y la fecha del requerimiento. Todos los
	 * requerimientos del mismo producto para la misma fecha serán mostrados en un sólo requerimiento comprimido con la cantidad requerida sumarizada.
	 * @param requerimientos. Requerimientos sin comprimir.
	 * @return List<RequerimientoComprimidoDTO>. Retorna una lista con los requerimientos comprimidos.
	 */
	private List<RequerimientoCompraDTO> comprimirRequerimientos(List<RequerimientoCompraDTO> requerimientos)
	{
		List<RequerimientoCompraDTO> comprimidos = new LinkedList<RequerimientoCompraDTO>();
		List<Integer> idsIncluidos = new LinkedList<Integer>();
		
		//la lista de ids contiene arrays de enteros donde la posición i de dicha lista almacena un array con los ids de los requerimientos comprimidos 
		//en la posición i de la lista de requerimientos comprimidos.
		ids = new LinkedList<List<Integer>>();
		
		for(int i=0; i< requerimientos.size(); i++)
		{
			//requerimiento comprimido que será resultado de la iteración
			RequerimientoCompraDTO requerimientoComprimido = new RequerimientoCompraDTO();
			
			//obtenemos las propiedades del requerimiento para comprarlo con los demás requerimientos
			int idRequerimiento1 = requerimientos.get(i).getIdRequerimientoCompra();
			int elemento1 = requerimientos.get(i).getRequerimientoMaterial().getProducto().getElemento().getCodigo();
			int material1 = requerimientos.get(i).getRequerimientoMaterial().getProducto().getMaterial().getCodigo();
			int medidaFija1 = requerimientos.get(i).getRequerimientoMaterial().getProducto().getMedidaFija().getCodigo();
			double medidaVariable11 = requerimientos.get(i).getMedidaVariable1();
			double medidaVariable12 = requerimientos.get(i).getMedidaVariable2();
			Date fecha1 = requerimientos.get(i).getFechaRequerimientoCompra();
			
			
			//inicializamos los valores de la cantidad requerida. Cuando se compriman requerimientos, lse sumarizan sus cantidades requeridas
			int cantidadRequerida = requerimientos.get(i).getCantidadRequerida();
			
			
			//cargamos las propiedades del requerimiento comprimido, excepto la cantidad requerida.
			requerimientoComprimido.getRequerimientoMaterial().setProducto(requerimientos.get(i).getRequerimientoMaterial().getProducto());
			requerimientoComprimido.setMedidaVariable1(requerimientos.get(i).getMedidaVariable1());
			requerimientoComprimido.setMedidaVariable2(requerimientos.get(i).getMedidaVariable2());
			requerimientoComprimido.setFechaRequerimientoCompra(requerimientos.get(i).getFechaRequerimientoCompra());
			
			
			//si el requerimiento de compra ya ha sido tratado, no se vuelve a evualuar y se pasa al siguiente requerimiento
			if(!idsIncluidos.contains(idRequerimiento1))
			{
				//creamos la lista de ids que sirven como mapeo entre el requerimiento comprimido y los requerimientos que han sido comprimidos
				List<Integer> idsComprimidos = new LinkedList<Integer>();
				
				//agregamos el requerimiento 1 a la lista de ids comprimidos
				idsComprimidos.add(idRequerimiento1);
				
				//comenzamos a iterar los requerimientos 2 desde el requerimiento 1 en adelante
				for(int j=i; j<requerimientos.size(); j++)
				{
					//obtenemos las propiedades del requerimiento 2
					int idRequerimiento2 = requerimientos.get(j).getIdRequerimientoCompra();
					
					//sólo realizamos las comparaciones siguientes si el requerimiento 1 es diferente del 2 y si el requerimiento 2 no ha sido tratado con anterioridad
					if(idRequerimiento1 != idRequerimiento2 && !idsIncluidos.contains(idRequerimiento2)){
						
						//obtenemos las propiedades del requerimiento 2
						int elemento2 = requerimientos.get(j).getRequerimientoMaterial().getProducto().getElemento().getCodigo();
						int material2 = requerimientos.get(j).getRequerimientoMaterial().getProducto().getMaterial().getCodigo();
						int medidaFija2 = requerimientos.get(j).getRequerimientoMaterial().getProducto().getMedidaFija().getCodigo();
						double medidaVariable21 = requerimientos.get(j).getMedidaVariable1();
						double medidaVariable22 = requerimientos.get(j).getMedidaVariable2();
						Date fecha2 = requerimientos.get(j).getFechaRequerimientoCompra();
						
						
						//si ambos requerimientos requieren el mismo producto para la misma fecha
						if(elemento1 == elemento2 && material1 == material2 && medidaFija1 == medidaFija2 && medidaVariable11 == medidaVariable21 && medidaVariable12 == medidaVariable22 && fecha1.compareTo(fecha2) == 0)
						{
							//sumamos la cantidad requerida del requerimiento al requerimiento comprimido
							cantidadRequerida = cantidadRequerida + requerimientos.get(j).getCantidadRequerida();
							
							//agregamos el requerimiento 2 a la lista de ids comprimidos
							idsComprimidos.add(idRequerimiento2);
							
							//si se comprime el requerimiento 2, lo agregamos a la lista de ids incluidos
							idsIncluidos.add(idRequerimiento2);
						}
					}
				}
				
				//seteamos las medidas variables al requerimiento comprimido
				requerimientoComprimido.setCantidadRequerida(cantidadRequerida);
				
				//agregamos el requerimiento comprimido resultante a la lista de requerimientos requeridos
				comprimidos.add(requerimientoComprimido);
				
				//agregamos la lista de ids comprimidos a la lista de ids
				ids.add(idsComprimidos);
				
				//marcamos el requerimiento 1 como tratado
				idsIncluidos.add(idRequerimiento1);
			}			
		}
		
		return comprimidos;
	}
	
	/**
	 * Método que valida que las cantidades a comprar ingresadas en la tabla sean correctas
	 */
	private boolean validarCantidades()
	{
		try{
			for(int i=1; i<ftRequerimientosCompra.getRowCount(); i++)
			{
				//recuperamos el checkbox y verificamos si está seleccionado para validar la cantidad a comprar ingresada.
				//sólo se validan las cantidades de los renglones seleccionados
				SimpleCheckBox seleccionado = (SimpleCheckBox) ftRequerimientosCompra.getWidget(i, COL_CHECK_RC);
				
				if(seleccionado.getValue())
				{
					//validamos la cantidad
					String cantidadString = ((TextBox) ftRequerimientosCompra.getWidget(i, COL_CANTIDAD_COMPRAR_RC)).getText();
					
					int cantidad = Integer.parseInt(cantidadString);
					
					if(cantidad <= 0)
						throw new Exception();
				}
			}
			
			return true;
		}
		
		catch(Exception e)
		{
			Window.alert("La cantidad a comprar debe ser un entero mayor que cero. Revise los valores ingresados");
			return false;
		}
		

	}
	
	/**
	 * Método llama a la pantalla para imprimir el presupuesto
	 */
	private void imprimir()
	{
		List<RequerimientoCompraDTO> requerimientosAImprimir = new LinkedList<RequerimientoCompraDTO>();
		
		for(int i=1; i<ftRequerimientosCompra.getRowCount(); i++)
		{
			SimpleCheckBox seleccionado = (SimpleCheckBox) ftRequerimientosCompra.getWidget(i, COL_CHECK_RC);
			
			if(seleccionado.getValue())
			{
				//obtenemos la cantidad a comprar como un entero
				int cantidad = Integer.parseInt(((TextBox) ftRequerimientosCompra.getWidget(i, COL_CANTIDAD_COMPRAR_RC)).getText());
				
				//asignamos la cantidad a comprar al objeto dto requerimiento de compra
				requerimientosComprimidos.get(i-1).setCantidadAComprar(cantidad);
				
				//agregamos el requerimiento a la lista de requerimientos por imprimir
				requerimientosAImprimir.add(requerimientosComprimidos.get(i-1));
			}
		}
		
		for(int i=0; i<productosAdicionales.size(); i++)
		{
			//obtenemos la cantidad a comprar de la tabla de productos adicionales
			int cantidad = Integer.parseInt(((Label) ftProductosAdicionales.getWidget(i+1, COL_CANTIDAD_COMPRAR_PA)).getText());
			
			//creamos un requerimiento a partir del producto adicional
			RequerimientoCompraDTO requerimiento = new RequerimientoCompraDTO();
			
			requerimiento.getRequerimientoMaterial().setProducto(productosAdicionales.get(i));
			requerimiento.setFechaRequerimientoCompra(null);
			requerimiento.setMedidaVariable1(productosAdicionales.get(i).getMedidaVariable1());
			requerimiento.setMedidaVariable2(productosAdicionales.get(i).getMedidaVariable2());
			requerimiento.setCantidadRequerida(0);
			requerimiento.setCantidadAComprar(cantidad);
			
			//agregamos el requerimiento a la lista de requerimientos por imprimir
			requerimientosAImprimir.add(requerimiento);
		}
		
		//llamamos al popup que permite imprimir el presupuesto
		final P_ImprimirPresupuesto popUp = new P_ImprimirPresupuesto(requerimientosAImprimir);
		popUp.setGlassEnabled(true);
		popUp.center();
		popUp.show();
	}
	
	/**
	 * Método que cuenta los requerimientos seleccionados y productos adicionales cargados
	 * @return productosCargados. Retorna la suma de requerimientos seleccionados y productos adicionales cargados
	 */
	private int productosCargados()
	{
		int productosCargados = 0;
		
		for(int i = 1; i<ftRequerimientosCompra.getRowCount(); i++)
		{
			SimpleCheckBox seleccionado = (SimpleCheckBox) ftRequerimientosCompra.getWidget(i, COL_CHECK_RC);
			
			if(seleccionado.getValue())
				productosCargados++;
		}
		
		productosCargados = productosCargados + productosAdicionales.size();
				
		return productosCargados;
	}
}